"""
系统设置API路由
"""
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
from fastapi.responses import FileResponse
from motor.motor_asyncio import AsyncIOMotorDatabase
from bson import ObjectId
from datetime import datetime
import logging
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import asyncio
import os
import subprocess
from pathlib import Path

from app.api.deps import get_db, get_current_user
from app.models.settings import (
    SystemSettingsModel,
    SystemSettingsResponse,
    GeneralSettingsUpdate,
    SecuritySettingsUpdate,
    NotificationSettingsUpdate,
    SystemSettingsUpdate,
    BackupSettingsUpdate,
    BackupRecord,
    BackupRecordList,
    EmailTestRequest,
    GeneralSettings,
    SecuritySettings,
    NotificationSettings,
    SystemSettings,
    BackupSettings
)
from app.core.permissions import Permissions, require_permission
from app.core.response import success_response, error_response, ErrorTypes, ErrorMessages, ApiResponse
from app.core.config import settings

logger = logging.getLogger(__name__)
router = APIRouter()


async def get_system_settings(db: AsyncIOMotorDatabase) -> SystemSettingsModel:
    """获取系统设置"""
    settings_doc = await db.system_settings.find_one({})
    
    if not settings_doc:
        # 如果没有设置记录，创建默认设置
        default_settings = SystemSettingsModel()
        settings_dict = default_settings.model_dump(exclude={"id"})
        settings_dict["created_at"] = datetime.utcnow()
        settings_dict["updated_at"] = datetime.utcnow()
        
        result = await db.system_settings.insert_one(settings_dict)
        settings_dict["id"] = str(result.inserted_id)
        return SystemSettingsModel(**settings_dict)
    
    settings_doc["id"] = str(settings_doc["_id"])
    del settings_doc["_id"]

    backup_doc = settings_doc.get("backup", {}) or {}
    # 兼容旧字段命名
    if "backup_retention_count" in backup_doc and "max_backup_count" not in backup_doc:
        backup_doc["max_backup_count"] = backup_doc["backup_retention_count"]
    # 合并默认备份配置，填充缺失字段
    default_backup = BackupSettings().model_dump()
    default_backup.update(backup_doc)
    settings_doc["backup"] = default_backup

    return SystemSettingsModel(**settings_doc)


@router.get("/", response_model=ApiResponse, summary="获取系统设置")
async def get_settings(
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """获取系统设置"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        settings_model = await get_system_settings(db)
        
        settings_data = SystemSettingsResponse(
            general=settings_model.general,
            security=settings_model.security,
            notification=settings_model.notification,
            system=settings_model.system,
            backup=settings_model.backup,
            updated_at=settings_model.updated_at,
            updated_by=settings_model.updated_by
        )
        
        return success_response(data=settings_data.model_dump(), message="获取系统设置成功")
        
    except Exception as e:
        logger.error(f"获取系统设置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取系统设置失败"
        )


@router.put("/general", response_model=ApiResponse, summary="更新基本设置")
async def update_general_settings(
    update_data: GeneralSettingsUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """更新基本设置"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取当前设置
        current_settings = await get_system_settings(db)
        
        # 确保current_settings是SystemSettingsModel对象
        if not isinstance(current_settings, SystemSettingsModel):
            logger.error(f"获取到的设置不是SystemSettingsModel对象: {type(current_settings)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="系统设置数据格式错误"
            )
        
        # 更新字段
        update_dict = update_data.model_dump(exclude_unset=True)
        if update_dict:
            # 更新基本设置
            for key, value in update_dict.items():
                setattr(current_settings.general, key, value)
            
            # 确保有有效的ID
            if not current_settings.id:
                logger.error("系统设置缺少有效的ID")
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="系统设置ID无效"
                )
            
            # 更新数据库
            await db.system_settings.update_one(
                {"_id": ObjectId(current_settings.id)},
                {
                    "$set": {
                        "general": current_settings.general.model_dump(),
                        "updated_at": datetime.utcnow(),
                        "updated_by": current_user.get("user_id")
                    }
                }
            )
        
        return success_response(message="基本设置更新成功")
        
    except Exception as e:
        logger.error(f"更新基本设置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新基本设置失败"
        )


@router.put("/security", response_model=ApiResponse, summary="更新安全设置")
async def update_security_settings(
    update_data: SecuritySettingsUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """更新安全设置"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取当前设置
        current_settings = await get_system_settings(db)
        
        # 确保current_settings是SystemSettingsModel对象
        if not isinstance(current_settings, SystemSettingsModel):
            logger.error(f"获取到的设置不是SystemSettingsModel对象: {type(current_settings)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="系统设置数据格式错误"
            )
        
        # 更新字段
        update_dict = update_data.model_dump(exclude_unset=True)
        if update_dict:
            # 更新安全设置
            for key, value in update_dict.items():
                setattr(current_settings.security, key, value)
            
            # 确保有有效的ID
            if not current_settings.id:
                logger.error("系统设置缺少有效的ID")
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="系统设置ID无效"
                )
            
            # 更新数据库
            await db.system_settings.update_one(
                {"_id": ObjectId(current_settings.id)},
                {
                    "$set": {
                        "security": current_settings.security.model_dump(),
                        "updated_at": datetime.utcnow(),
                        "updated_by": current_user.get("user_id")
                    }
                }
            )
        
        return success_response(message="安全设置更新成功")
        
    except Exception as e:
        logger.error(f"更新安全设置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新安全设置失败"
        )


@router.put("/notification", response_model=ApiResponse, summary="更新通知设置")
async def update_notification_settings(
    update_data: NotificationSettingsUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """更新通知设置"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取当前设置
        current_settings = await get_system_settings(db)
        
        # 确保current_settings是SystemSettingsModel对象
        if not isinstance(current_settings, SystemSettingsModel):
            logger.error(f"获取到的设置不是SystemSettingsModel对象: {type(current_settings)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="系统设置数据格式错误"
            )
        
        # 更新字段
        update_dict = update_data.model_dump(exclude_unset=True)
        if update_dict:
            # 更新通知设置
            for key, value in update_dict.items():
                setattr(current_settings.notification, key, value)
            
            # 确保有有效的ID
            if not current_settings.id:
                logger.error("系统设置缺少有效的ID")
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="系统设置ID无效"
                )
            
            # 更新数据库
            await db.system_settings.update_one(
                {"_id": ObjectId(current_settings.id)},
                {
                    "$set": {
                        "notification": current_settings.notification.model_dump(),
                        "updated_at": datetime.utcnow(),
                        "updated_by": current_user.get("user_id")
                    }
                }
            )
        
        return success_response(message="通知设置更新成功")
        
    except Exception as e:
        logger.error(f"更新通知设置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新通知设置失败"
        )


@router.put("/system", response_model=ApiResponse, summary="更新系统配置")
async def update_system_settings(
    update_data: SystemSettingsUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """更新系统配置"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取当前设置
        current_settings = await get_system_settings(db)
        
        # 确保current_settings是SystemSettingsModel对象
        if not isinstance(current_settings, SystemSettingsModel):
            logger.error(f"获取到的设置不是SystemSettingsModel对象: {type(current_settings)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="系统设置数据格式错误"
            )
        
        # 更新字段
        update_dict = update_data.model_dump(exclude_unset=True)
        if update_dict:
            # 更新系统设置
            for key, value in update_dict.items():
                setattr(current_settings.system, key, value)
            
            # 确保有有效的ID
            if not current_settings.id:
                logger.error("系统设置缺少有效的ID")
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="系统设置ID无效"
                )
            
            # 更新数据库
            await db.system_settings.update_one(
                {"_id": ObjectId(current_settings.id)},
                {
                    "$set": {
                        "system": current_settings.system.model_dump(),
                        "updated_at": datetime.utcnow(),
                        "updated_by": current_user.get("user_id")
                    }
                }
            )
        
        return success_response(message="系统配置更新成功")
        
    except Exception as e:
        logger.error(f"更新系统配置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新系统配置失败"
        )


@router.put("/backup", response_model=ApiResponse, summary="更新备份设置")
async def update_backup_settings(
    update_data: BackupSettingsUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """更新备份设置"""
    try:
        # 检查权限 - 将User对象转换为字典格式
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取当前设置
        current_settings = await get_system_settings(db)
        
        # 更新字段
        update_dict = update_data.model_dump(exclude_unset=True)
        if "backup_retention_count" in update_dict and "max_backup_count" not in update_dict:
            update_dict["max_backup_count"] = update_dict.pop("backup_retention_count")
        if update_dict:
            # 更新备份设置
            for key, value in update_dict.items():
                setattr(current_settings.backup, key, value)
            
            # 更新数据库
            await db.system_settings.update_one(
                {"_id": ObjectId(current_settings.id)},
                {
                    "$set": {
                        "backup": current_settings.backup.model_dump(),
                        "updated_at": datetime.utcnow(),
                        "updated_by": current_user.get("user_id")
                    }
                }
            )
        
        return success_response(message="备份设置更新成功")
        
    except Exception as e:
        logger.error(f"更新备份设置失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新备份设置失败"
        )


@router.post("/test-email", response_model=ApiResponse, summary="测试邮件发送")
async def test_email(
    test_request: EmailTestRequest,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """测试邮件发送"""
    try:
        # 检查权限 - 将User对象转换为字典格式
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取邮件设置
        settings_model = await get_system_settings(db)
        notification_settings = settings_model.notification
        
        if not notification_settings.email_enabled:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="邮件通知未启用"
            )
        
        # 发送测试邮件
        await send_test_email(notification_settings, test_request)
        
        return success_response(message="测试邮件发送成功")
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"测试邮件发送失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"测试邮件发送失败: {str(e)}"
        )


async def send_test_email(notification_settings: NotificationSettings, test_request: EmailTestRequest):
    """发送测试邮件"""
    try:
        # 创建邮件消息
        msg = MIMEMultipart()
        msg['From'] = notification_settings.smtp_username
        msg['To'] = test_request.to_email
        msg['Subject'] = test_request.subject
        
        # 添加邮件内容
        body = test_request.content
        msg.attach(MIMEText(body, 'plain', 'utf-8'))
        
        # 连接SMTP服务器并发送邮件
        if notification_settings.smtp_encryption == "ssl":
            server = smtplib.SMTP_SSL(notification_settings.smtp_host, notification_settings.smtp_port)
        else:
            server = smtplib.SMTP(notification_settings.smtp_host, notification_settings.smtp_port)
            if notification_settings.smtp_encryption == "tls":
                server.starttls()
        
        server.login(notification_settings.smtp_username, notification_settings.smtp_password)
        server.send_message(msg)
        server.quit()
        
    except Exception as e:
        logger.error(f"SMTP邮件发送失败: {str(e)}")
        raise e


@router.get("/backup/history", response_model=ApiResponse, summary="获取备份历史")
async def get_backup_history(
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """获取备份历史"""
    try:
        # 检查权限 - 将User对象转换为字典格式
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 获取备份历史
        backup_items: List[BackupRecord] = []
        cursor = db.backup_records.find().sort("created_at", -1)
        async for record in cursor:
            created_at = record.get("created_at")
            if isinstance(created_at, str):
                try:
                    created_at = datetime.fromisoformat(created_at)
                except ValueError:
                    created_at = datetime.utcnow()
            elif created_at is None:
                created_at = datetime.utcnow()

            backup_items.append(
                BackupRecord(
                    id=str(record.get("_id")),
                    filename=record.get("filename", ""),
                    size=record.get("size", 0),
                    status=record.get("status", "unknown"),
                    created_at=created_at,
                    created_by=record.get("created_by")
                )
            )
        
        backup_list = BackupRecordList(
            items=backup_items,
            total=len(backup_items)
        )
        
        return success_response(data=backup_list.model_dump(), message="获取备份历史成功")
        
    except Exception as e:
        logger.error(f"获取备份历史失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取备份历史失败"
        )


@router.post("/backup/create", response_model=ApiResponse, summary="创建备份任务")
async def create_backup(
    background_tasks: BackgroundTasks,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """创建系统备份"""
    try:
        # 检查权限 - 将User对象转换为字典格式
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 添加后台任务
        background_tasks.add_task(perform_backup, db, current_user.get("user_id"))
        
        return success_response(message="备份任务已启动，请稍后查看备份历史")
        
    except Exception as e:
        logger.error(f"创建备份失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="创建备份失败"
        )


async def perform_backup(db: AsyncIOMotorDatabase, user_id: str):
    """执行备份操作"""
    backup_filename = f"backup_{datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}.json"
    backup_path = Path("backups") / backup_filename
    # 读取备份配置
    retention_count = 10
    compression_enabled = True
    encryption_enabled = False
    try:
        settings_doc = await db.system_settings.find_one({}, {"backup": 1})
        if settings_doc:
            backup_config = settings_doc.get("backup", {}) or {}
            retention_count = int(backup_config.get("max_backup_count", backup_config.get("backup_retention_count", 10)) or 10)
            compression_enabled = bool(backup_config.get("backup_compression", True))
            encryption_enabled = bool(backup_config.get("backup_encryption", False))
    except Exception as config_error:
        logger.warning(f"读取备份配置失败，使用默认配置: {str(config_error)}")
    
    try:
        # 确保备份目录存在
        backup_path.parent.mkdir(exist_ok=True)
        
        # 创建备份记录
        backup_record = {
            "filename": backup_filename,
            "size": 0,
            "status": "running",
            "created_at": datetime.utcnow(),
            "created_by": user_id,
            "compression": compression_enabled,
            "encryption": encryption_enabled
        }
        
        result = await db.backup_records.insert_one(backup_record)
        backup_id = result.inserted_id
        
        # 模拟备份过程（实际应该导出数据库数据）
        await asyncio.sleep(2)  # 模拟备份时间
        
        # 创建一个简单的备份文件
        backup_data = {
            "backup_time": datetime.utcnow().isoformat(),
            "database": settings.MONGODB_DATABASE,
            "collections": ["users", "projects", "tasks", "requirements", "defects"]
        }
        
        import json
        with open(backup_path, 'w', encoding='utf-8') as f:
            json.dump(backup_data, f, ensure_ascii=False, indent=2)
        
        # 获取文件大小
        file_size = backup_path.stat().st_size
        
        # 更新备份记录
        await db.backup_records.update_one(
            {"_id": backup_id},
            {
                "$set": {
                    "size": file_size,
                    "status": "success"
                }
            }
        )
        
        logger.info(f"备份完成: {backup_filename}")

        # 按照保留策略清理旧备份
        if retention_count and retention_count > 0:
            total_records = await db.backup_records.count_documents({})
            excess = total_records - retention_count
            if excess > 0:
                logger.info(f"超过备份保留上限，开始清理最早的 {excess} 个备份")
                old_cursor = db.backup_records.find().sort("created_at", 1).limit(excess)
                async for old_record in old_cursor:
                    old_path = Path("backups") / old_record.get("filename", "")
                    try:
                        if old_path.exists():
                            old_path.unlink()
                    except Exception as remove_err:
                        logger.warning(f"删除旧备份文件失败: {old_path} - {str(remove_err)}")
                    await db.backup_records.delete_one({"_id": old_record["_id"]})
        
    except Exception as e:
        logger.error(f"备份失败: {str(e)}")
        # 更新备份记录为失败状态
        await db.backup_records.update_one(
            {"_id": backup_id},
            {
                "$set": {
                    "status": "failed"
                }
            }
        )


@router.delete("/backup/{backup_id}", response_model=ApiResponse, summary="删除备份")
async def delete_backup(
    backup_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """删除备份"""
    try:
        # 检查权限
        require_permission(current_user, Permissions.SYSTEM_MANAGE)
        
        # 查找备份记录
        backup_record = await db.backup_records.find_one({"_id": ObjectId(backup_id)})
        if not backup_record:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="备份记录不存在"
            )
        
        # 删除备份文件
        backup_path = Path("backups") / backup_record["filename"]
        if backup_path.exists():
            backup_path.unlink()
        
        # 删除数据库记录
        await db.backup_records.delete_one({"_id": ObjectId(backup_id)})
        
        return success_response(message="备份删除成功")
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除备份失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="删除备份失败"
        )


@router.get("/backup/download/{backup_id}", summary="下载备份文件")
async def download_backup(
    backup_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
):
    """下载备份文件"""
    try:
        require_permission(current_user, Permissions.SYSTEM_MANAGE)

        backup_record = await db.backup_records.find_one({"_id": ObjectId(backup_id)})
        if not backup_record:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="备份记录不存在"
            )

        backup_filename = backup_record.get("filename")
        if not backup_filename:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="备份记录缺少文件信息"
            )

        backup_path = Path("backups") / backup_filename
        if not backup_path.exists():
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="备份文件不存在"
            )

        media_type = "application/json"
        if backup_filename.endswith(".zip"):
            media_type = "application/zip"

        return FileResponse(
            path=backup_path,
            media_type=media_type,
            filename=backup_filename
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"下载备份失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="下载备份失败"
        )